package com.demo.xj_plane.controller;

import com.demo.xj_plane.common.utils.GlobalConstant;
import com.demo.xj_plane.common.utils.MessageUtils;
import com.demo.xj_plane.entity.*;
import com.demo.xj_plane.service.XjLiveSaService;
import com.demo.xj_plane.service.XjMesFcService;
import com.demo.xj_plane.service.XjMixProductService;
import com.demo.xj_plane.service.XjSelfObsService;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 自观数据解析，并入库
 */
@Slf4j
@Component
public class XjSelfObsTask {

    private static final Map<String, Map<String, Object>> picMixClearedFolder = new HashMap<>();
    @Autowired
    private XjSelfObsService xjSelfObsService;
    @Autowired
    private XjMesFcService xjMesFcService;
    @Autowired
    private XjLiveSaService xjLiveSaService;
    @Autowired
    private XjMixProductService xjMixProductService;
    @Value("${dataConfig.xjSelfObsPath}")
    private String xjSelfObsPath;
    @Value("${dataConfig.xjLiveMesPath}")
    private String xjLiveMesPath;
    @Value("${dataConfig.productPicPath}")
    private String productPicPath;
    @Value("${dataConfig.rootUri}")
    private String rootUri;
    private final Set<String> processedFiles = new HashSet<>(); // 记录已处理的文件名(自观）
    private String lastClearedFolderName; // 记录上一次清空的记录文件夹
    private final Set<String> processedFilesBw = new HashSet<>(); // 记录已处理的文件名（报文）
    private String lastClearedBwFolderName; // 记录上一次清空的记录文件夹

    /**
     * 获取当前时间，北京时
     *
     */
    private static String getCurrentTime() {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 格式化时间为yyyyMMddHHmm
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String formattedTime = now.format(formatter);
        return formattedTime;
    }

    public static void main(String[] args) {
        // parseAndInsert("9_FCST_C_ZBBB_20241011103238_V-FUSN-REFP-SWFC-20241011120000-20241011180000-ACHN-SWH-3,M-7,COLOR.png", "D:/remaps_data2/test1/20240509");
    }

    /**
     * 转换发布中心字码
     *
     * @param releaseCenter 发布中心代码
     * @return 转换后的发布中心名称
     */
    public static String convertReleaseCenter(String releaseCenter) {
        Map<String, List<String>> dicMap = new HashMap<>();
        dicMap.put("MHQX", GlobalConstant.mhqxDicList);
        dicMap.put("LD", GlobalConstant.ldDicList);
        dicMap.put("HSD", GlobalConstant.hsdDicList);
        dicMap.put("DQQX", GlobalConstant.dqqxDicList);

        // 遍历字典映射，寻找匹配的发布中心
        for (Map.Entry<String, List<String>> entry : dicMap.entrySet()) {
            String key = entry.getKey();
            List<String> valueList = entry.getValue();
            if (valueList.contains(releaseCenter)) {
                return key; // 找到匹配，返回对应的键
            }
        }

        return "XXXX"; // 如果没有找到，返回默认值
    }

    public void myTask() {
        // 创建线程池
        ScheduledExecutorService exec = Executors.newScheduledThreadPool(5);
        // 每隔1分钟读取一次的入库文件
        exec.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                log.info(".....自观数据解析线程启动.....");
                try {
                    //xjSelfObsTaskStart();
                } catch (Exception e) {
                    log.error("自观数据解析线程启动发生异常: {}", e.getMessage());
                }
            }
        }, 0, 1, TimeUnit.MINUTES);

        exec.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                log.info(".....预报，实况数据处理线程开始.....");
                try {
                    // 执行预报，实况接口，每1分钟
                    //xjLiveMesTaskStart();
                } catch (Exception e) {
                    log.error("预报，实况数据处理线程任务发生异常: {}", e.getMessage());
                }
            }
        }, 0, 1, TimeUnit.MINUTES);

        exec.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                log.info(".....图片产品处理线程开始.....");
                try {
                    // 执行预报，实况接口，每1分钟
                    picProductTaskStart();
                } catch (Exception e) {
                    log.error("图片产品处理线程任务发生异常: {}", e.getMessage());
                }
            }
        }, 0, 1, TimeUnit.MINUTES);
    }

    private void xjSelfObsTaskStart() {
        // 获取读取文件夹的时间
        String folderName = getCurTime();
        // 如果当前文件夹与上次清空记录的文件夹不同，则清空记录
        if (!folderName.equals(lastClearedFolderName)) {
            processedFiles.clear(); // 清空已处理文件记录
            lastClearedFolderName = folderName; // 更新上次清空记录的日期
        }
        String basePath = xjSelfObsPath + folderName;

        // 读取文件夹中的 JSON 文件
        File folder = new File(basePath);
        if (!folder.exists() || !folder.isDirectory()) {
            System.out.println("路径不存在或不是文件夹: " + basePath);
            return;
        }

        // 遍历 JSON 文件
        File[] files = folder.listFiles((dir, name) -> name.toLowerCase().endsWith(".json"));
        if (files != null) {
            for (File file : files) {
                if (!processedFiles.contains(file.getName())) {
                    try {
                        // 读取 JSON 文件内容
                        String jsonData = new String(Files.readAllBytes(file.toPath()));
                        List<XjSelfObsEntity> observations = new Gson().fromJson(jsonData, new TypeToken<List<XjSelfObsEntity>>() {
                        }.getType());
                        System.out.println("自观数据为=" + observations);

                        // 保存数据到数据库
                        //xjSelfObsService.saveObsBatch(observations);
                        xjSelfObsService.saveBatch(observations);
                        // 将处理过的文件名加入已处理列表中
                        processedFiles.add(file.getName());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                } else {
                    System.out.println("该自观数据文件夹已经处理过: " + file.getName());
                }
            }
        } else {
            System.out.println("该文件夹中没有 JSON 文件: " + basePath);
        }
    }

    /**
     * 获取当前读取文件夹小时
     */
    private String getCurTime() {
        // 获取当前时间，减去两分钟
        LocalDateTime currentTime = LocalDateTime.now(ZoneOffset.UTC).minusMinutes(2);
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMddHH");
        // 获取读取文件夹名称
        String folderName = dtf.format(currentTime);
        return folderName;
    }

    private void xjLiveMesTaskStart() throws IOException {
        // 获取读取文件夹的时间
        String folderName = getCurTime();
        String basePath = xjLiveMesPath + folderName;

        // 如果当前文件夹（报文）与上次清空记录的文件夹不同，则清空记录
        if (!folderName.equals(lastClearedBwFolderName)) {
            processedFilesBw.clear(); // 清空已处理文件记录
            lastClearedBwFolderName = folderName; // 更新上次清空记录的日期
        }
        // 读取文件夹中的 JSON 文件
        File folder = new File(basePath);
        if (!folder.exists() || !folder.isDirectory()) {
            System.out.println("路径不存在或不是文件夹: " + basePath);
            return;
        }

        // 遍历 JSON 文件
        File[] files = folder.listFiles((dir, name) -> name.toLowerCase().endsWith(".json"));
        if (files != null) {
            for (File file : files) {
                if (!processedFilesBw.contains(file.getName())) {
                    String jsonData = new String(Files.readAllBytes(file.toPath()));
                    List<WeatherDataEntity> weatherDataList = new Gson().fromJson(jsonData, new TypeToken<List<WeatherDataEntity>>() {
                    }.getType());
                    // 将处理过的文件名加入已处理列表中
                    processedFilesBw.add(file.getName());
                    for (WeatherDataEntity data : weatherDataList) {
                        // 暂时不管国际机场（Z开头的）
                        String reportAirport = MessageUtils.getReportAirport(data.getCONTENT());
                        if (!reportAirport.startsWith("Z")) {
                            continue;
                        }
                        String type = data.getTT();
                        if ("FC".equals(type) || "FT".equals(type)) {
                            saveToFcTable(data);
                        } else if ("SA".equals(type) || "SP".equals(type)) {
                            saveToSaTable(data);
                        }
                    }
                } else {
                    System.out.println("该报文文件夹已经处理过: " + file.getName());
                }
            }
        } else {
            System.out.println("该文件夹中没有 JSON 文件: " + basePath);
        }
    }

    /*
    * 所有天气预报类产品
    * 存储预报产品URI
    * */
    private void picProductTaskStart() {
        String fchartRootPath = productPicPath + GlobalConstant.picTypeMap.get("SWFC");
        String uatpRootPath = productPicPath + GlobalConstant.picTypeMap.get("UATP");
        String hgt0cPath = productPicPath + GlobalConstant.picTypeMap.get("HGT0C");
        // 高空风温预告图产品
        if (checkFoldExist(uatpRootPath)) {
            String lastUatpFolder = getLastFolder(uatpRootPath);
            String uatpPath = String.format("%s%s%s",uatpRootPath, "/", lastUatpFolder);
            String uriRootUatp = String.format("%s%s%s",rootUri,GlobalConstant.picTypeMap.get("UATP"),lastUatpFolder);
            parseAndInsert("uatp", uatpPath,uriRootUatp);
        }
        // 重要天气预告图产品
        if (checkFoldExist(fchartRootPath)) {
            String lastFchartFolder = getLastFolder(fchartRootPath);
            String fchartPath = String.format("%s%s%s", fchartRootPath, "/", lastFchartFolder);
            String uriRootUatp = String.format("%s%s%s",rootUri,GlobalConstant.picTypeMap.get("SWFC"),lastFchartFolder);
            parseAndInsert("uatp", fchartPath,uriRootUatp);
        }
        // 0℃高度层
        if (checkFoldExist(hgt0cPath)) {
            String lastHgt0cFolder = getLastFolder(hgt0cPath);
            String hgt0cFolderPath = String.format("%s%s", hgt0cPath, lastHgt0cFolder);
            String uriRootHgt0c = String.format("%s%s%s",rootUri,GlobalConstant.picTypeMap.get("HGT0C"),lastHgt0cFolder);
            parseAndInsert("noHeight", hgt0cFolderPath,uriRootHgt0c);
        }

    }

    /*
    * 判断文件夹是否存在
    * */
    private boolean checkFoldExist(String folder){
        // 进入指定目录
        File baseFolder = new File(folder);
        // 检查目录是否存在
        return baseFolder.exists() && baseFolder.isDirectory();
    }

    /**
     * 解析，保存预报数据
     *
     * @param data
     */
    private void saveToFcTable(WeatherDataEntity data) {
        XjMesFcEntity entity = new XjMesFcEntity();
        entity.setCccc(MessageUtils.getReportAirport(data.getCONTENT()));
        entity.setType(data.getTT());
        entity.setIssueDateTime(convertToNewFormat(data.getISSUE_DATE_TIME()));
        entity.setHeadDateTime(convertToNewFormat(data.getHEAD_DATE_TIME()));
        entity.setContent(data.getCONTENT());
        entity.setIntm(getCurrentTime()); // 获取当前时间戳
        System.out.println("FC结果为===" + entity);
        if (!xjMesFcService.selectExist(entity.getCccc(), entity.getType(), entity.getIssueDateTime())) {
            xjMesFcService.save(entity);
        } else {
            System.out.println("FC重复数据===" + entity.getCccc() + "type===" + entity.getType());
        }

    }

    /**
     * 解析保存，实况数据
     *
     * @param data
     */
    private void saveToSaTable(WeatherDataEntity data) throws IOException {
        XjLiveSaEntity entity = new XjLiveSaEntity();
        entity.setCccc(MessageUtils.getReportAirport(data.getCONTENT()));
        entity.setType(data.getTT());
        entity.setODateTime(convertToNewFormat(data.getO_DATE_TIME()));
        entity.setHeadDateTime(convertToNewFormat(data.getHEAD_DATE_TIME()));
        entity.setContent(data.getCONTENT());
        // 定义content时间正则表达式
        Pattern pattern = Pattern.compile("(\\d{6}Z)");
        Matcher matcher = pattern.matcher(data.getCONTENT());

        if (matcher.find()) {
            // 找到时间戳
            String timeStamp = matcher.group(1); // 260700Z
            entity.setContentTime(timeStamp);
        }

        entity.setWindSpeed(MessageUtils.getWdAndWsFromReportMessage(data.getCONTENT()));

        // 定义风变化正则表达式
        String regex = "\\s*(\\d{3}V\\d{3})\\s*";
        Pattern pattern1 = Pattern.compile(regex);
        Matcher matcher1 = pattern1.matcher(data.getCONTENT());

        if (matcher1.find()) {
            // 提取风变化（去掉前后的空格）
            String windChange = matcher.group(1).trim(); // 020V120
            entity.setWindChange(windChange);
        }
        // 可见度
        entity.setVisibility(MessageUtils.getVisFromReportMessage(data.getCONTENT()));
        // getTfromMessage 温度 getDpfromMessage 露点气温
        entity.setTem(MessageUtils.getTfromMessage(data.getCONTENT()));
        entity.setDptem(MessageUtils.getDpfromMessage(data.getCONTENT()));

        entity.setIntm(getCurrentTime()); // 获取当前时间戳

        // 获取天气现象
        entity.setEvent(MessageUtils.getWeatherPhenomenonFromMessage(data.getCONTENT()));
        System.out.println("SA结果为===" + entity);

        if (!xjLiveSaService.selectExist(entity.getCccc(), entity.getType(), entity.getODateTime())) {
            xjLiveSaService.save(entity);
        } else {
            System.out.println("SA重复数据===" + entity.getCccc() + "type===" + entity.getType());
        }

    }

    /**
     * 获取当前时间，世界时
     *
     * @return
     */
    private String getCurrentTimeUtc() {
        // 获取当前时间，世界时
        LocalDateTime currentTime = LocalDateTime.now(ZoneOffset.UTC);
        // 转换为dt
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String utcTime = currentTime.format(formatter);
        return utcTime;
    }

    public String convertToNewFormat(String dateStr) {
        // 定义原始日期格式
        DateTimeFormatter originalFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 定义目标日期格式
        DateTimeFormatter targetFormat = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

        // 将字符串解析为 LocalDateTime
        LocalDateTime dateTime = LocalDateTime.parse(dateStr, originalFormat);
        // 格式化为目标字符串格式
        return dateTime.format(targetFormat);
    }

    private void parseAndInsert(String fileType, String picPath,String uriRoot) {

        List<XjMixProductEntity> dataLst = new ArrayList<>();
        // 读取文件夹中的 JSON 文件
        File folder = new File(picPath);
        // 过滤重复文件夹
        Map<String, Object> curMap = picMixClearedFolder.computeIfAbsent(fileType, k -> new HashMap<>());
        String folderName = (String) curMap.get("folderName");
        // 如果文件夹发生变化，清空已处理文件集合
        if (folderName == null || !folderName.equals(picPath)) {
            curMap.put("processedFiles", new HashSet<String>());
            curMap.put("folderName", picPath);
            System.out.println("已更新文件夹: " + picPath);
        }
        // 获取目录下所有文件
        File[] files = folder.listFiles();
        Set<String> processedFilesPic = new HashSet<>();
        if (curMap != null) {
            processedFilesPic = (Set<String>) curMap.get("processedFiles");
        }
        curMap.put("processedFiles", processedFilesPic);
        if (files != null) {
            for (File file : files) {
                if (!processedFilesPic.contains(file.getName()) && file.isFile()) {
                    //重要天气预告图
                    if(fileType == "fchart"){
                        try {
                            XjMixProductEntity xpe = fchart(file, processedFilesPic, uriRoot, fileType);
                            dataLst.add(xpe);
                        }catch (Exception e){
                            continue;
                        }
                    }
                    //高空风文图
                    if(fileType == "uatp"){
                        try {
                            XjMixProductEntity xpe = uatp(file, processedFilesPic, uriRoot, fileType);
                            dataLst.add(xpe);
                        }catch (Exception e){
                            continue;
                        }
                    }
                    //无高度层产品：0℃高度层、总云量、TTINDEX、SWEATINDEX、KINDEX、et.al.
                    if(fileType == "noHeight"){
                        try {
                            XjMixProductEntity xpe = tempof0(file, processedFilesPic, uriRoot);
                            dataLst.add(xpe);
                        }catch (Exception e){
                            continue;
                        }
                    }

                } else {
                    System.out.println("该图片文件已入库....===" + file.getName());
                }
            }
        }
        // 批量保存入库
        xjMixProductService.saveBatch(dataLst);
    }

    private XjMixProductEntity fchart(File file,Set<String> processedFilesPic,String uriRoot,String fileType) throws Exception{
        String fileName = file.getName();
        if (fileName.contains("COLOR") || fileName.endsWith("xml")) { // 确保有足够的元素
            throw new Exception("不存储彩色及xml格式文件: " + fileName);
        }
        processedFilesPic.add(fileName);
        XjMixProductEntity xpe = new XjMixProductEntity();
        // 使用下划线分割文件名
        String[] parts = fileName.split("_");
        if (parts.length < 6) { // 至少需要 ZBBB 和后续信息
            throw new Exception("文件名格式不正确: " + fileName);
        }

        String releaseCenter = parts[3]; // ZBBB
        //xpe.setReleaseCenter(convertReleaseCenter(releaseCenter));
        xpe.setReleaseCenter(releaseCenter);
        String[] detailParts = parts[5].split("-"); // 使用 parts[5] 分割详细部分
        if (detailParts.length < 8) { // 确保有足够的元素
            throw new Exception("详细信息格式不正确: " + fileName);
        }
        // 起报时间: 20241011120000
        String forecastTime = detailParts[4];
        xpe.setForecastTime(forecastTime);
        // 预报时间: 20241011180000
        String reportingTime = detailParts[5];
        xpe.setReportingTime(reportingTime);
        // 区域: ACHN
        String region = detailParts[6];
        xpe.setRegion(region);
        // 层次: SWH
        String level = detailParts[7];
        xpe.setLevel(level);
        // 拼接文件URI
        String absolutePath = String.format("%s%s%s", uriRoot,"/", fileName);
        xpe.setPath(absolutePath);
        // 文件类型
        xpe.setProductType(fileType.toUpperCase());
        // 添加入库时间
        xpe.setIntm(getCurrentTime());
        return xpe;
    }
    private XjMixProductEntity uatp(File file,Set<String> processedFilesPic,String uriRoot,String fileType) throws Exception{
        String fileName = file.getName();
        processedFilesPic.add(fileName);
        XjMixProductEntity xpe = new XjMixProductEntity();
        // 使用下划线分割文件名
        String[] parts = fileName.split("_");
        if (parts.length < 6) { // 至少需要 ZBBB 和后续信息
            throw new Exception("文件名格式不正确: " + fileName);
        }

        String releaseCenter = parts[3]; // ZBBB
        xpe.setReleaseCenter(releaseCenter);
        String[] detailParts = parts[5].split("-"); // 使用 parts[5] 分割详细部分
        if (detailParts.length < 8) { // 确保有足够的元素
            throw new Exception("详细信息格式不正确: " + fileName);
        }
        // 起报时间: 20241011120000
        String forecastTime = detailParts[4];
        xpe.setForecastTime(forecastTime);
        // 预报时间: 20241011180000
        String reportingTime = detailParts[5];
        xpe.setReportingTime(reportingTime);
        // 区域: ACHN
        String region = detailParts[6];
        xpe.setRegion(region);
        // 层次: SWH
        String level = detailParts[7];
        xpe.setLevel(level);
        // 拼接文件URI
        String absolutePath = String.format("%s%s%s", uriRoot,"/", fileName);
        xpe.setPath(absolutePath);
        // 文件类型
        xpe.setProductType(fileType.toUpperCase());
        // 添加入库时间
        xpe.setIntm(getCurrentTime());
        return xpe;
    }

    /*
    * 0摄氏度高度层图片产品
    * */
    private XjMixProductEntity tempof0(File file,Set<String> processedFilesPic,String uriRoot) throws Exception{
        String fileName = file.getName();
        processedFilesPic.add(fileName);
        XjMixProductEntity xpe = new XjMixProductEntity();
        // 使用下划线分割文件名
        String[] parts = fileName.split("_");
        if (parts.length < 6) { // 至少需要 ZBBB 和后续信息
            throw new Exception("文件名格式不正确: " + fileName);
        }

        String releaseCenter = parts[3]; // ZBBB
        //xpe.setReleaseCenter(convertReleaseCenter(releaseCenter));
        xpe.setReleaseCenter(releaseCenter);
        int partsCount = parts.length;
        String[] detailParts = parts[partsCount-1].split("-"); // 使用 parts[5] 分割详细部分
        if (detailParts.length < 8) { // 确保有足够的元素
            throw new Exception("详细信息格式不正确: " + fileName);
        }
        // 起报时间: 20241011120000
        String forecastTime = detailParts[4];
        xpe.setForecastTime(forecastTime);
        // 预报时间: 20241011180000
        String reportingTime = detailParts[5];
        xpe.setReportingTime(reportingTime);
        // 区域: ACHN
        String region = detailParts[6];
        xpe.setRegion(region);
        // 层次: SWH
        String level = detailParts[7];
        if(level.endsWith(".png")){
            level = level.substring(0,level.indexOf("."));
        }
        xpe.setLevel(level);
        // 拼接文件URI
        String absolutePath = String.format("%s%s%s", uriRoot,"/", fileName);
        xpe.setPath(absolutePath);
        // 文件类型
        String fileType = detailParts[3];
        xpe.setProductType(fileType);
        // 添加入库时间
        xpe.setIntm(getCurrentTime());
        return xpe;
    }

    /*
    * 获取路径中最新文件夹
    * */
    private String getLastFolder(String path){
        String finalFolderName = "";
        if(checkFoldExist(path)){
            File pathFile = new File(path);
            File[] subFolders = pathFile.listFiles();
            for (int i = 0;i<subFolders.length-1;i++) {
                String folderName = subFolders[i].getName();
                if(!folderName.startsWith("2")){
                    return "";
                }
                for(int j = i+1;j<subFolders.length;j++){
                    if(subFolders[i].lastModified() > subFolders[j].lastModified()){
                        finalFolderName = subFolders[i].getName();
                    }
                }
            }
        }
        return finalFolderName;
    }

}
